package com.strato.mvc.api.v1_0_0.control;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.strato.base.cache.v1_0_0.TimedReference;
import com.strato.base.osgi.v1_0_0.BundleUtil;
import com.strato.base.osgi.v1_0_0.Ordered;
import com.strato.mvc.api.v1_0_0.activator.Activator;
import com.strato.mvc.api.v1_0_0.model.ModelAndView;
import com.strato.mvc.api.v1_0_0.util.RequestMeta;
import com.strato.mvc.api.v1_0_0.util.RequestParser;

public abstract class AbstractHttpInvoker implements HttpInvoker {

	@Override
	public final ModelAndView invoke(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc) throws Exception {
		List<HttpInvokerInterceptor> interceptors=getInterceptors(request,response,pvc);
		try{
			ModelAndView mav=new ModelAndView();
			boolean continuee=true;
			for(HttpInvokerInterceptor interceptor:interceptors){
				continuee=continuee&&interceptor.beforeInvocation(request,response,pvc,mav,this);
			}
			if(!continuee){
				return mav;
			}
			doInvoke(request, response, pvc,mav);
			for(HttpInvokerInterceptor interceptor:interceptors){
				interceptor.invocationSuccess(request,response,pvc,mav,this);
			}
			return mav;
		}catch(Exception e){
			e.printStackTrace();
			for(HttpInvokerInterceptor interceptor:interceptors){
				interceptor.invocationFailed(request,response,pvc,e,this);
			}
			throw new RuntimeException(e);
		}finally{
			for(HttpInvokerInterceptor interceptor:interceptors){
				interceptor.invokeFinally(request,response,pvc,this);
			}
		}
	}

	private List<HttpInvokerInterceptor> getInterceptors(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc) {
		RequestMeta meta = RequestParser.parse(request);
		List<HttpInvokerInterceptor> interceptors = getAllInterceptors();
		for(Iterator<HttpInvokerInterceptor> iter=interceptors.iterator();iter.hasNext();){
			HttpInvokerInterceptor interceptor=iter.next();
			if(!interceptor.canHandle(request,response,pvc,meta,this)){
				iter.remove();
			}
		}
		Collections.sort(interceptors, Ordered.ASCEND);
		return interceptors;
	}

	private static TimedReference<List<HttpInvokerInterceptor>> _allInterceptors=null;
	private static int _allInterceptorsCacheTTL=60*1000;
	private static synchronized List<HttpInvokerInterceptor> getAllInterceptors() {
		if(_allInterceptors!=null&&!_allInterceptors.isExpired()&&_allInterceptors.getObject()!=null){
			return new ArrayList<HttpInvokerInterceptor>(_allInterceptors.getObject());
		}
		List<HttpInvokerInterceptor> interceptors = BundleUtil.getServices(Activator.getContext(), HttpInvokerInterceptor.class, null);
		_allInterceptors=new TimedReference<List<HttpInvokerInterceptor>>(interceptors,_allInterceptorsCacheTTL);
		return new ArrayList<HttpInvokerInterceptor>(interceptors);
	}

	public abstract void doInvoke(HttpServletRequest request, HttpServletResponse response, PathVariableCollector pvc,ModelAndView mav) throws Exception;

}
